/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ECMASCRIPT_HPROF_HEAP_SAMPLING_H
#define ECMASCRIPT_HPROF_HEAP_SAMPLING_H

#include <csignal>

#include "ecmascript/compiler/gate_meta_data.h"
#include "ecmascript/deoptimizer/deoptimizer.h"
#include "ecmascript/dfx/hprof/heap_profiler_interface.h"
#include "ecmascript/dfx/stackinfo/js_stackgetter.h"
#include "ecmascript/mem/heap.h"

namespace panda::ecmascript {

struct CallFrameInfo {
    std::string codeType = "";
    std::string functionName = "";
    int columnNumber = 0;
    int lineNumber = 0;
    int scriptId = 0;
    std::string url = "";
};
struct AllocationNode {
    std::map<size_t, unsigned int> allocations;
    std::map<MethodKey, struct AllocationNode> children;
    // const AllocationNode *pre_;
    CallFrameInfo callFrameInfo;
    size_t id = 0;
    size_t selfSize = 0;
};
struct Sample {
    Sample(size_t size, size_t nodeId, size_t ordinal)
        : size(size),
          nodeId(nodeId),
          ordinal(ordinal) {}
    const size_t size;
    const size_t nodeId;
    const size_t ordinal;
};
struct SamplingInfo {
    struct AllocationNode head;
    CVector<struct Sample> samples;
};

class HeapSampling {
public:
    HeapSampling(const EcmaVM *vm, Heap *const heap, uint64_t interval, int stackDepth);
    std::unique_ptr<struct SamplingInfo> GetAllocationProfile();
    void ImplementSampling(Address addr, size_t size);
    virtual ~HeapSampling();

private:
    void GetStack();
    struct AllocationNode *PushAndGetNode();
    CallFrameInfo GetMethodInfo(MethodKey methodKey);
    struct AllocationNode *FindOrAddNode(struct AllocationNode *node, struct MethodKey &methodKey);
    bool PushStackInfo(struct MethodKey &methodKey);
    bool PushFrameInfo(const FrameInfoTemp &frameInfoTemp);
    std::string GetRunningState(RunningState state, kungfu::DeoptType type);
    void ResetFrameLength();
    void *GetMethodIdentifier(Method *method, const FrameIterator &it);
    struct AllocationNode *GetStackSignalHandler();
    uint32_t CreateNodeId();
    uint64_t CreateSampleId();
    void FillScriptIdAndStore();
    const EcmaVM *vm_;
    Heap *const heap_;
    uint64_t rate_;
    std::unique_ptr<struct SamplingInfo> samplingInfo_;
    int stackDepth_;
    AllocationInspector allocationInspector_;
    uint32_t nodeId_ = 0;
    size_t SampleId_ = 0;
    CMap<struct MethodKey, struct CallFrameInfo> stackInfoMap_;
    CVector<struct MethodKey> frameStack_;
    CMap<std::string, int> scriptIdMap_;
    CVector<FrameInfoTemp> frameInfoTemps_;
};
}  // namespace panda::ecmascript
#endif  // ECMASCRIPT_HPROF_HEAP_SAMPLING_H